/**
 * 图片压缩工具函数
 * @description 提供图片压缩、格式转换、尺寸调整、缩略图生成等功能
 * @author 系统开发团队
 * @version 1.0.0
 */

// ==================== 接口定义 ====================

/**
 * 图片压缩选项接口
 * @description 定义图片压缩的各种参数选项
 */
export interface CompressOptions {
    /** 最大宽度（像素） */
    maxWidth?: number
    /** 最大高度（像素） */
    maxHeight?: number
    /** 压缩质量，范围0-1，1为最高质量 */
    quality?: number
    /** 输出格式，支持jpeg、png、webp */
    format?: 'jpeg' | 'png' | 'webp'
    /** 是否保持宽高比，默认为true */
    maintainAspectRatio?: boolean
}

/**
 * 压缩结果接口
 * @description 定义图片压缩后的结果信息
 */
export interface CompressResult {
    /** 压缩后的文件对象 */
    file: File
    /** 原始文件大小（字节） */
    originalSize: number
    /** 压缩后文件大小（字节） */
    compressedSize: number
    /** 压缩比例，范围0-1 */
    compressionRatio: number
    /** 压缩后图片宽度（像素） */
    width: number
    /** 压缩后图片高度（像素） */
    height: number
}

// ==================== 核心压缩函数 ====================

/**
 * 压缩单张图片
 * @description 使用Canvas API压缩图片，支持尺寸调整、质量控制和格式转换
 * @param {File} file 原始图片文件
 * @param {CompressOptions} options 压缩选项，可选
 * @returns {Promise<CompressResult>} 压缩结果，包含压缩后的文件和统计信息
 * @example
 * const result = await compressImage(file, {
 *   maxWidth: 800,
 *   maxHeight: 600,
 *   quality: 0.8,
 *   format: 'jpeg'
 * })
 * console.log('压缩比例:', result.compressionRatio)
 */
export const compressImage = async (
    file: File,
    options: CompressOptions = {}
): Promise<CompressResult> => {
    // 设置默认压缩选项
    const {
        maxWidth = 1200,
        maxHeight = 800,
        quality = 0.8,
        format = 'jpeg',
        maintainAspectRatio = true
    } = options

    return new Promise((resolve, reject) => {
        // 创建Canvas用于图片处理
        const canvas = document.createElement('canvas')
        const ctx = canvas.getContext('2d')

        if (!ctx) {
            reject(new Error('无法创建Canvas上下文'))
            return
        }

        // 创建Image对象加载图片
        const img = new Image()

        img.onload = () => {
            try {
                // 计算压缩后的尺寸
                let { width, height } = img

                if (maintainAspectRatio) {
                    // 保持宽高比，按比例缩放
                    const ratio = Math.min(maxWidth / width, maxHeight / height)
                    if (ratio < 1) {
                        width *= ratio
                        height *= ratio
                    }
                } else {
                    // 不保持宽高比，直接限制最大尺寸
                    width = Math.min(width, maxWidth)
                    height = Math.min(height, maxHeight)
                }

                // 设置canvas尺寸
                canvas.width = width
                canvas.height = height

                // 在canvas上绘制压缩后的图片
                ctx.drawImage(img, 0, 0, width, height)

                // 将canvas内容转换为Blob
                canvas.toBlob(
                    (blob) => {
                        if (blob) {
                            // 创建压缩后的文件对象
                            const compressedFile = new File([blob], file.name, {
                                type: `image/${format}`,
                                lastModified: Date.now()
                            })

                            // 构建压缩结果对象
                            const result: CompressResult = {
                                file: compressedFile,
                                originalSize: file.size,
                                compressedSize: compressedFile.size,
                                compressionRatio: (file.size - compressedFile.size) / file.size,
                                width: Math.round(width),
                                height: Math.round(height)
                            }

                            resolve(result)
                        } else {
                            reject(new Error('图片压缩失败'))
                        }
                    },
                    `image/${format}`,
                    quality
                )
            } catch (error) {
                reject(error)
            }
        }

        img.onerror = () => {
            reject(new Error('图片加载失败'))
        }

        // 设置图片源并开始加载
        img.src = URL.createObjectURL(file)
    })
}

/**
 * 批量压缩图片
 * @description 对多个图片文件进行批量压缩处理
 * @param {File[]} files 图片文件数组
 * @param {CompressOptions} options 压缩选项，可选
 * @returns {Promise<CompressResult[]>} 压缩结果数组
 * @example
 * const results = await compressImages([file1, file2, file3], {
 *   maxWidth: 800,
 *   quality: 0.7
 * })
 * results.forEach(result => {
 *   console.log(`${result.file.name}: ${result.compressionRatio.toFixed(2)}`)
 * })
 */
export const compressImages = async (
    files: File[],
    options: CompressOptions = {}
): Promise<CompressResult[]> => {
    const results: CompressResult[] = []

    // 逐个处理每个文件
    for (const file of files) {
        try {
            const result = await compressImage(file, options)
            results.push(result)
        } catch (error) {
            console.error(`压缩文件 ${file.name} 失败:`, error)
            // 如果压缩失败，返回原文件信息
            results.push({
                file,
                originalSize: file.size,
                compressedSize: file.size,
                compressionRatio: 0,
                width: 0,
                height: 0
            })
        }
    }

    return results
}

// ==================== 图片信息处理 ====================

/**
 * 获取图片信息
 * @description 获取图片的宽度、高度和文件大小信息
 * @param {File} file 图片文件
 * @returns {Promise<{width: number, height: number, size: number}>} 图片信息对象
 * @example
 * const info = await getImageInfo(file)
 * console.log(`图片尺寸: ${info.width}x${info.height}, 大小: ${info.size}字节`)
 */
export const getImageInfo = (file: File): Promise<{ width: number, height: number, size: number }> => {
    return new Promise((resolve, reject) => {
        const img = new Image()

        img.onload = () => {
            resolve({
                width: img.width,
                height: img.height,
                size: file.size
            })
        }

        img.onerror = () => {
            reject(new Error('无法获取图片信息'))
        }

        img.src = URL.createObjectURL(file)
    })
}

/**
 * 验证图片文件
 * @description 验证图片文件的有效性，包括文件类型和大小检查
 * @param {File} file 文件对象
 * @param {number} maxSize 最大文件大小（MB），默认5MB
 * @returns {{valid: boolean, error?: string}} 验证结果
 * @example
 * const validation = validateImageFile(file, 10)
 * if (!validation.valid) {
 *   console.error('文件验证失败:', validation.error)
 * }
 */
export const validateImageFile = (file: File, maxSize: number = 5) => {
    // 检查文件类型是否为图片
    if (!file.type.startsWith('image/')) {
        return { valid: false, error: '只能上传图片文件' }
    }

    // 检查文件大小是否超过限制
    const sizeInMB = file.size / 1024 / 1024
    if (sizeInMB > maxSize) {
        return { valid: false, error: `图片大小不能超过 ${maxSize}MB` }
    }

    return { valid: true }
}

// ==================== 缩略图生成 ====================

/**
 * 生成缩略图
 * @description 为图片生成指定尺寸的缩略图
 * @param {File} file 原始图片文件
 * @param {number} width 缩略图宽度，默认200像素
 * @param {number} height 缩略图高度，默认200像素
 * @returns {Promise<File>} 缩略图文件对象
 * @example
 * const thumbnail = await generateThumbnail(file, 150, 150)
 * console.log('缩略图生成成功:', thumbnail.name)
 */
export const generateThumbnail = async (
    file: File,
    width: number = 200,
    height: number = 200
): Promise<File> => {
    return new Promise((resolve, reject) => {
        const canvas = document.createElement('canvas')
        const ctx = canvas.getContext('2d')

        if (!ctx) {
            reject(new Error('无法创建Canvas上下文'))
            return
        }

        const img = new Image()

        img.onload = () => {
            // 设置canvas尺寸为缩略图尺寸
            canvas.width = width
            canvas.height = height

            // 在canvas上绘制缩略图
            ctx.drawImage(img, 0, 0, width, height)

            // 转换为JPEG格式的File对象
            canvas.toBlob(
                (blob) => {
                    if (blob) {
                        const thumbnailFile = new File([blob], `thumb_${file.name}`, {
                            type: 'image/jpeg',
                            lastModified: Date.now()
                        })
                        resolve(thumbnailFile)
                    } else {
                        reject(new Error('生成缩略图失败'))
                    }
                },
                'image/jpeg',
                0.8
            )
        }

        img.onerror = () => {
            reject(new Error('图片加载失败'))
        }

        img.src = URL.createObjectURL(file)
    })
}

// ==================== 工具函数 ====================

/**
 * 格式化文件大小
 * @description 将字节数转换为人类可读的文件大小字符串
 * @param {number} bytes 字节数
 * @returns {string} 格式化后的文件大小字符串
 * @example
 * const sizeStr = formatFileSize(1024 * 1024) // 返回: "1.00 MB"
 */
export const formatFileSize = (bytes: number): string => {
    if (bytes === 0) return '0 B'

    const k = 1024
    const sizes = ['B', 'KB', 'MB', 'GB']
    const i = Math.floor(Math.log(bytes) / Math.log(k))

    return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]
}

/**
 * 获取支持的图片格式
 * @description 返回浏览器支持的图片MIME类型数组
 * @returns {string[]} 支持的图片格式数组
 * @example
 * const formats = getSupportedFormats()
 * console.log('支持的格式:', formats)
 */
export const getSupportedFormats = (): string[] => {
    return ['image/jpeg', 'image/png', 'image/gif', 'image/webp']
}

/**
 * 检查浏览器是否支持WebP格式
 * @description 检测当前浏览器是否支持WebP图片格式
 * @returns {Promise<boolean>} 是否支持WebP格式
 * @example
 * const supportsWebP = await isWebPSupported()
 * if (supportsWebP) {
 *   console.log('浏览器支持WebP格式')
 * }
 */
export const isWebPSupported = (): Promise<boolean> => {
    return new Promise((resolve) => {
        const canvas = document.createElement('canvas')
        canvas.width = 1
        canvas.height = 1

        canvas.toBlob(
            (blob) => {
                resolve(blob?.type === 'image/webp')
            },
            'image/webp'
        )
    })
} 